package controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import model.RefreshStatusItem;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import utils.CustomizeProgressBar;
import utils.Utils;
import utils.XmlParser;
import android.app.Activity;
import android.content.Context;
import android.database.DataSetObserver;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import app.cloudstringers.R;
import app.cloudstringers.StatusTab;
import app.cloudstringers.Upload;
import define.API;
import define.Constants;
import define.Key;

/**
 * Apply only for Upload class and Convert class
 * 
 * @author Administrator
 * 
 */
public class RefreshStatusAsync extends AsyncTask<String, Void, Boolean> {
	/**
	 * String section
	 */
	private static final String TAG = RefreshStatusAsync.class.getSimpleName();

	// All static variables
	private static final String KEY_CURRENT_SIZE = "CURRENTSIZE";
	private static final String KEY_FILE_NAME = "FILENAME";

	// XML node keys
	private static final String KEY_FILE = "FILE";
	private static final String KEY_UPLOAD_TIME = "UPLOADTIME";
	private static final String KEY_TOTAL_SIZE = "TOTALSIZE";
	private static final String KEY_UPLOAD_ID = "UPLOAD_ID";

	private String FILE_NAME = null, CURRENT_SIZE = null, TOTAL_SIZE = null,
			UPLOAD_TIME = null, UPLOAD_ID = null;

	private String ID = null;
	/**
	 * Data section
	 */
	private LinkedList<String> mLlCurrentFileName = new LinkedList<String>();
	private LinkedList<String> mLlCurrentSize = new LinkedList<String>();

	private RefreshStatusItemAdapter refreshStatusItemAdapter = null;

	/**
	 * View section
	 */
	private ListView mLvRefreshStatusItem;

	/**
	 * Others section
	 */
	private Context context;
	private XmlParser mXMLParser;

	public RefreshStatusAsync(final Context context) {
		this.context = context;

		if (!context.getClass().getSimpleName()
				.equals(define.Class.CLASS_PRIORITY_LIST)) {
			((Activity) context).runOnUiThread(new Runnable() {

				@Override
				public void run() {
					// Should create new adapter in here, not in Background
					// Thread
					refreshStatusItemAdapter = new RefreshStatusItemAdapter(
							context, R.layout.simple_list_item_upload,
							Constants.mLlItems);
				}
			});
		}
	}

	@Override
	protected Boolean doInBackground(String... params) {
		// Set data
		ID = params[0];

		/**
		 * Call Status API to show the files in List View
		 */
		try {
			HttpClient mHttpClient = new DefaultHttpClient();
			HttpPost mHttpPost = new HttpPost(API.UPLOAD_STATUS);
			List<NameValuePair> mNameValues = new ArrayList<NameValuePair>(2);

			mNameValues
					.add(new BasicNameValuePair(Key.KEY_GLOBAL_ID, params[0]));
			mNameValues.add(new BasicNameValuePair(Key.KEY_STATE, params[1]));

			mHttpPost.setEntity(new UrlEncodedFormEntity(mNameValues));

			HttpResponse mHttpResponse = mHttpClient.execute(mHttpPost);
			HttpEntity mHttpEntity = mHttpResponse.getEntity();

			String XML = EntityUtils.toString(mHttpEntity);

			mXMLParser = new XmlParser();
			Document mDocument = mXMLParser.getDomElement(XML);

			// StringBuilder mSb = new StringBuilder();
			NodeList mNodeList = mDocument.getElementsByTagName(KEY_FILE);
			for (int i = 0; i < mNodeList.getLength(); i++) {
				if (mNodeList.item(i).getNodeType() == Node.ELEMENT_NODE) {
					Element element = (Element) mNodeList.item(i);

					FILE_NAME = mXMLParser.getValue(element, KEY_FILE_NAME);
					CURRENT_SIZE = mXMLParser.getValue(element,
							KEY_CURRENT_SIZE);
					TOTAL_SIZE = mXMLParser.getValue(element, KEY_TOTAL_SIZE);
					UPLOAD_TIME = mXMLParser.getValue(element, KEY_UPLOAD_TIME);
					UPLOAD_ID = mXMLParser.getValue(element, KEY_UPLOAD_ID);

					// increasedSize = currentSize
					// Get last currentSize
					RefreshStatusItem item = new RefreshStatusItem(
							CURRENT_SIZE, FILE_NAME, TOTAL_SIZE, UPLOAD_ID,
							UPLOAD_TIME, "0");

					// Add to current size array, file name array
					mLlCurrentFileName.add(FILE_NAME);
					mLlCurrentSize.add(CURRENT_SIZE);

					// adding all the elements
					Constants.mLlItems.add(item);

					// mSb.append(item.getFileName() + ", " +
					// item.getPauseValue()
					// + "\n");
				}
			}

			// NOTIFICATION = mSb.toString();

			/**
			 * Check size of file in the array list to decide the file has state
			 * : Uploading, Stopped
			 */
			detectSizeChange();

			return true;
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (ConnectTimeoutException e) {
			e.printStackTrace();
			return false;
		} catch (SocketException e) {
			e.printStackTrace();
			return false;
		} catch (SocketTimeoutException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	@Override
	protected void onPreExecute() {
		super.onPreExecute();

		((Activity) context).runOnUiThread(new Runnable() {

			@Override
			public void run() {
				// Clear data first before use new data
				if (Constants.mLlItems != null && !Constants.mLlItems.isEmpty()) {
					Constants.mLlItems.clear();
				}

				mLvRefreshStatusItem = (ListView) ((Activity) context)
						.findViewById(R.id.lv_in_upload);
				mLvRefreshStatusItem.requestLayout();
			}
		});
	}

	@Override
	protected void onPostExecute(Boolean result) {
		super.onPostExecute(result);

		// Enable all tab widget
		Utils.enableTabWidgetInStatusTab(Constants.STATUS_TAB_SIZE);

		Class<?> object = null;
		try {
			object = Class.forName(context.getClass().getName());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

		if (!result) {
			Constants.utils.showConnectionTimeoutDialog(context, object);
		} else {
			((Activity) context).runOnUiThread(new Runnable() {

				@Override
				public void run() {
					// if (!NOTIFICATION.equals(""))
					// Toast.makeText(context, NOTIFICATION,
					// Toast.LENGTH_SHORT).show();

					/**
					 * Add sleep time to avoid Empty frame always show in Upload
					 * Tab
					 */
					try {
						Thread.sleep(500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}

					if (refreshStatusItemAdapter != null
							&& !refreshStatusItemAdapter.isEmpty()) {
						// If the server responses data
						// Set adapter for list
						mLvRefreshStatusItem
								.setAdapter(refreshStatusItemAdapter);

						// Notify user that data has already changed
						mLvRefreshStatusItem.requestLayout();
						refreshStatusItemAdapter.notifyDataSetChanged();
					} else if (refreshStatusItemAdapter != null
							&& refreshStatusItemAdapter.isEmpty()) {
						// If the server responses null data
						// refresh to see null page
						mLvRefreshStatusItem
								.setAdapter(refreshStatusItemAdapter);

						// Notify user that data has already changed
						mLvRefreshStatusItem.requestLayout();
						refreshStatusItemAdapter.notifyDataSetChanged();

						refreshStatusItemAdapter = null;
					}

					// Start refresh timer immediately
					// when finish pause progress
					if (!Constants.REFRESH_IN_UPLOAD) {
						if (StatusTab.mTimerUpload == null) {
							StatusTab.mTimerUpload = new Timer();

							if (StatusTab.mTtRefreshUpload == null) {
								StatusTab.mTtRefreshUpload = new TimerTask() {
									@Override
									public void run() {
										StatusTab.refreshTab(Upload.class);
									}
								};
							}

							StatusTab.mTimerUpload
									.schedule(
											StatusTab.mTtRefreshUpload,
											define.Timer.TIMER_REFRESH_DELAY_IN_STATUS_TAB,
											define.Timer.TIMER_REFRESH_IN_STATUS_TAB);
						}

						// Set boolean not to allow refresh two times in the
						// same time
						Constants.REFRESH_IN_UPLOAD = true;
					}
				}
			});
		}
	}

	/**
	 * Basic methods
	 */
	private void detectSizeChange() {
		// When having the changed about data, need change temp data also
		if (Constants.FIRST_LAUNCH_TIME) {
			// Clear array list
			if (!Constants.mLlIncreasedSizeRefresh.isEmpty()) {
				Constants.mLlIncreasedSizeRefresh.clear();
			}

			Constants.mLlIncreasedSizeRefresh = new LinkedList<String>(
					mLlCurrentSize);
			Constants.FIRST_LAUNCH_TIME = false;
		} else {
			if (mLlCurrentSize.size() > Constants.mLlIncreasedSizeRefresh
					.size()) {
				// Clear array list
				if (!Constants.mLlIncreasedSizeRefresh.isEmpty()) {
					Constants.mLlIncreasedSizeRefresh.clear();
				}

				Constants.mLlIncreasedSizeRefresh = new LinkedList<String>(
						mLlCurrentSize);
			} else if (mLlCurrentSize.size() < Constants.mLlIncreasedSizeRefresh
					.size()) {
				// Clear array list
				if (!Constants.mLlIncreasedSizeRefresh.isEmpty()) {
					Constants.mLlIncreasedSizeRefresh.clear();
				}

				Constants.mLlIncreasedSizeRefresh = new LinkedList<String>(
						mLlCurrentSize);
			}
		}
	}

	public class RefreshStatusItemAdapter extends
			ArrayAdapter<RefreshStatusItem> {
		// calculate uploading progress
		private double current_size = 0, total_size = 1;

		private int textViewResourceId;

		private class ViewHolder {
			private TextView mTvTitle;
			private TextView mTvContent;
			private CustomizeProgressBar customizePb;
		}

		public RefreshStatusItemAdapter(Context context,
				int textViewResourceId, LinkedList<RefreshStatusItem> mAlItems) {
			super(context, textViewResourceId, mAlItems);

			this.textViewResourceId = textViewResourceId;
		}

		@Override
		public View getView(final int position, View convertView,
				ViewGroup parent) {
			// Initialize variables
			ViewHolder viewHolder = null;
			if (convertView == null) {
				viewHolder = new ViewHolder();
				LayoutInflater mLiInflater = (LayoutInflater) context
						.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

				convertView = mLiInflater.inflate(textViewResourceId, null);

				viewHolder.mTvTitle = (TextView) convertView
						.findViewById(R.id.tv_title_item_in_status);
				viewHolder.mTvContent = (TextView) convertView
						.findViewById(R.id.tv_content_item_in_status);
				viewHolder.customizePb = (CustomizeProgressBar) convertView
						.findViewById(R.id.pb_item_in_status);

				convertView.setTag(viewHolder);
			} else {
				viewHolder = (ViewHolder) convertView.getTag();
			}

			if (position < Constants.mLlItems.size()
					&& position < Constants.mLlIncreasedSizeRefresh.size()) {
				// Set data
				viewHolder.mTvTitle.setText(Constants.mLlItems.get(position)
						.getFileName());
				viewHolder.mTvContent.setText(Constants.mLlItems.get(position)
						.getUploadTime());

				// Get current size & total size
				current_size = Double.parseDouble(Constants.mLlItems.get(
						position).getCurrentSize());
				total_size = Double.parseDouble(Constants.mLlItems
						.get(position).getTotalSize());

				int RESULT = (int) (100 * current_size / total_size);

				if (current_size == Double
						.valueOf(Constants.mLlIncreasedSizeRefresh
								.get(position))) {
					// Set Pause flag = 1 if the file has already stopped
					Constants.mLlItems.get(position).setPauseValue("1");

					viewHolder.customizePb.setProgress(RESULT);
					viewHolder.customizePb
							.setText(context.getString(R.string.uploading)
									+ " " + RESULT + "%");
				} else {
					// Replace with new data
					// Replace value Constants.mAlIncreasedSize[position] with
					// current
					Constants.mLlIncreasedSizeRefresh.set(position,
							String.valueOf(current_size));

					viewHolder.customizePb.setProgress(RESULT);
					viewHolder.customizePb
							.setText(context.getString(R.string.uploading)
									+ " " + RESULT + "%");
				}
			}

			return convertView;
		}

		@Override
		public void unregisterDataSetObserver(DataSetObserver observer) {
			if (observer != null) {
				super.unregisterDataSetObserver(observer);
			}
		}

		/**
		 * Basic methods
		 */
	}
}
